﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace Obra.Test
{
    /// <summary>
    /// An HTTP server used for unit testing.
    /// </summary>
    /// <remarks>
    /// <para>
    /// These are the facts.
    ///   1. Caller queues up the content to be returned.
    ///   2. The request is processed asynchronously.
    ///   3. The data returned is specified at the time of construction.
    ///   4. HTTP headers are hard-coded.
    ///     a. Content-Type: text/xml
    /// </para>
    /// <para>
    /// This code was inspired by the WCF REST toolkit code from Microsoft.
    /// </para>
    /// </remarks>
    class HttpServerQueuedContent :
        HttpServer
    {
        private readonly Queue<string> contentQueue = 
            new Queue<string>();

        /// <summary>
        /// The data to return for _every_ URL requested.
        /// </summary>
        internal Queue<string> ContentQueue
        {
            get { return contentQueue; }
        }

        private readonly Queue<IHttpRequestValidate> requestValidateQueue =
            new Queue<IHttpRequestValidate>();

        /// <summary>
        /// These validators are used to vaidate incoming requests.
        /// </summary>
        internal Queue<IHttpRequestValidate> RequestValidateQueue
        {
            get { return requestValidateQueue; }
        } 

        /// <summary>
        /// c-tor
        /// </summary>
        public HttpServerQueuedContent(
            Uri address)
            : base(address)
        {
        }

        /// <summary>
        /// Apply the queue of validators to the request.
        /// </summary>
        private void ValidateRequest(
            HttpListenerRequest request)
        {
            foreach (var validator in this.RequestValidateQueue)
            {
                validator.Validate(request);
            }
        }

        protected override void OnContextAvailable(
            IAsyncResult asyncResult)
        {
            HttpServerQueuedContent httpServer = 
                (HttpServerQueuedContent)asyncResult.AsyncState;

            try
            {
                asyncResult.AsyncWaitHandle.WaitOne();
                HttpListenerContext context = httpServer.HttpListener.EndGetContext(
                    asyncResult);

                HttpListenerRequest request = context.Request;
                this.ValidateRequest(request);

                HttpListenerResponse response = context.Response;

                string content = httpServer.ContentQueue.Dequeue();

                byte[] buffer = Encoding.UTF8.GetBytes(
                    content);

                response.Headers.Add("Content-Type: text/xml");

                response.ContentLength64 = buffer.Length;
                response.OutputStream.Write(buffer, 0, buffer.Length);
                response.Close();
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.ToString());
            }
            finally
            {
                if (httpServer.ContentQueue.Count > 0)
                {
                    httpServer.HttpListener.BeginGetContext(
                        this.OnContextAvailable,
                        httpServer);
                }
            }
        }
    }
}
